/**
 * 通用工具函数
 * @author 王勇程 <laughskydragon@qq.com>
 */

/**
 * 显示加载提示
 * @param {string} title 加载提示文字
 * @param {boolean} mask 是否显示透明蒙层，防止触摸穿透
 */
export function showLoading(title = '加载中...', mask = true) {
  uni.showLoading({
    title,
    mask
  })
}

/**
 * 隐藏加载提示
 */
export function hideLoading() {
  uni.hideLoading()
}

/**
 * 显示成功提示
 * @param {string} title 提示文字
 * @param {number} duration 显示时长，单位ms
 */
export function showSuccess(title = '操作成功', duration = 1500) {
  uni.showToast({
    title,
    icon: 'success',
    duration
  })
}

/**
 * 显示错误提示
 * @param {string} title 提示文字
 * @param {number} duration 显示时长，单位ms
 */
export function showError(title = '操作失败', duration = 2000) {
  uni.showToast({
    title,
    icon: 'none',
    duration
  })
}

/**
 * 显示警告提示
 * @param {string} title 提示文字
 * @param {number} duration 显示时长，单位ms
 */
export function showWarning(title = '请注意', duration = 2000) {
  uni.showToast({
    title,
    icon: 'none',
    duration
  })
}

/**
 * 统一错误处理
 * @param {Error|Object} error 错误对象
 * @param {string} defaultMessage 默认错误消息
 * @param {boolean} showToast 是否显示错误提示
 */
export function handleError(error, defaultMessage = '操作失败', showToast = true) {
  console.error('错误详情:', error)
  
  let errorMessage = defaultMessage
  
  // 解析错误消息
  if (error && typeof error === 'object') {
    if (error.message) {
      errorMessage = error.message
    } else if (error.msg) {
      errorMessage = error.msg
    } else if (error.data && error.data.message) {
      errorMessage = error.data.message
    } else if (error.data && error.data.msg) {
      errorMessage = error.data.msg
    }
  } else if (typeof error === 'string') {
    errorMessage = error
  }
  
  // 特殊错误码处理
  if (error && error.code) {
    switch (error.code) {
      case 1000002:
        errorMessage = 'access_token错误或过期'
        break
      case 1000005:
        errorMessage = 'user_token错误或过期，请重新登录'
        // 可以在这里触发重新登录逻辑
        break
      case 'NETWORK_ERROR':
        errorMessage = '网络连接失败，请检查网络设置'
        break
      case 'TIMEOUT':
        errorMessage = '请求超时，请稍后重试'
        break
    }
  }
  
  if (showToast) {
    showError(errorMessage)
  }
  
  return errorMessage
}

/**
 * 专门处理API响应错误
 * @param {Object} response API响应对象
 * @param {string} defaultMessage 默认错误消息
 * @param {boolean} showToast 是否显示错误提示
 * @returns {string} 错误消息
 */
export function handleApiError(response, defaultMessage = '请求失败', showToast = true) {
  console.error('API错误响应:', response)
  
  let errorMessage = defaultMessage
  let shouldRelogin = false
  
  if (response && typeof response === 'object') {
    // 处理标准API响应格式
    if (response.code !== undefined && response.code !== 0) {
      errorMessage = response.msg || response.message || defaultMessage
      
      // 根据错误码进行特殊处理
      switch (response.code) {
        case 1000001:
          errorMessage = 'access_token错误，请重试'
          break
        case 1000002:
          errorMessage = 'access_token过期，请重试'
          break
        case 1000005:
          errorMessage = '登录已过期，请重新登录'
          shouldRelogin = true
          break
        case 1000006:
          errorMessage = '用户不存在或已被禁用'
          shouldRelogin = true
          break
        case 1000007:
          errorMessage = '权限不足'
          break
        case 1000008:
          errorMessage = '参数错误'
          break
        case 1000009:
          errorMessage = '数据不存在'
          break
        case 1000010:
          errorMessage = '操作失败，请稍后重试'
          break
        default:
          // 保持原有错误消息
          break
      }
    }
    
    // 处理网络错误
    if (response.status) {
      switch (response.status) {
        case 400:
          errorMessage = '请求参数错误'
          break
        case 401:
          errorMessage = '未授权，请重新登录'
          shouldRelogin = true
          break
        case 403:
          errorMessage = '权限不足'
          break
        case 404:
          errorMessage = '请求的资源不存在'
          break
        case 500:
          errorMessage = '服务器内部错误'
          break
        case 502:
          errorMessage = '网关错误'
          break
        case 503:
          errorMessage = '服务暂时不可用'
          break
        default:
          errorMessage = `网络错误 (${response.status})`
          break
      }
    }
  }
  
  // 处理需要重新登录的情况
  if (shouldRelogin) {
    // 延迟执行，避免与当前操作冲突
    setTimeout(() => {
      // 这里可以调用store的logout方法或跳转到登录页
      try {
        // 如果有store，调用logout
        if (typeof getApp === 'function') {
          const app = getApp()
          if (app.$store && app.$store.dispatch) {
            app.$store.dispatch('user/logout')
          }
        }
      } catch (e) {
        console.warn('自动登出失败:', e)
      }
    }, 1000)
  }
  
  if (showToast) {
    showError(errorMessage)
  }
  
  return errorMessage
}

/**
 * 确认对话框
 * @param {string} content 对话框内容
 * @param {string} title 对话框标题
 * @param {string} confirmText 确认按钮文字
 * @param {string} cancelText 取消按钮文字
 * @returns {Promise<boolean>} 用户是否确认
 */
export function showConfirm(
  content = '确定要执行此操作吗？',
  title = '提示',
  confirmText = '确定',
  cancelText = '取消'
) {
  return new Promise((resolve) => {
    uni.showModal({
      title,
      content,
      confirmText,
      cancelText,
      success: (res) => {
        resolve(res.confirm)
      },
      fail: () => {
        resolve(false)
      }
    })
  })
}

/**
 * 格式化价格
 * @param {number|string} price 价格
 * @param {number} decimals 小数位数
 * @param {string} symbol 货币符号
 * @returns {string} 格式化后的价格
 */
export function formatPrice(price, decimals = 1, symbol = '¥') {
  const numPrice = parseFloat(price || 0)
  return `${symbol}${numPrice.toFixed(decimals)}`
}

/**
 * 格式化数字
 * @param {number|string} num 数字
 * @param {number} decimals 小数位数
 * @returns {string} 格式化后的数字
 */
export function formatNumber(num, decimals = 0) {
  const number = parseFloat(num || 0)
  return number.toFixed(decimals)
}

/**
 * 格式化涨跌幅
 * @param {number|string} change 涨跌值
 * @param {number} decimals 小数位数
 * @returns {string} 格式化后的涨跌幅
 */
export function formatChange(change, decimals = 1) {
  const changeValue = parseFloat(change || 0)
  if (changeValue > 0) {
    return `+${changeValue.toFixed(decimals)}`
  } else if (changeValue < 0) {
    return changeValue.toFixed(decimals)
  } else {
    return '0.0'
  }
}

/**
 * 格式化时间
 * @param {string|Date} time 时间
 * @param {string} format 格式化模式
 * @returns {string} 格式化后的时间
 */
export function formatTime(time, format = 'YYYY-MM-DD HH:mm:ss') {
  if (!time) return ''
  
  const date = new Date(time)
  if (isNaN(date.getTime())) return ''
  
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hours = String(date.getHours()).padStart(2, '0')
  const minutes = String(date.getMinutes()).padStart(2, '0')
  const seconds = String(date.getSeconds()).padStart(2, '0')
  
  return format
    .replace('YYYY', year)
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hours)
    .replace('mm', minutes)
    .replace('ss', seconds)
}

/**
 * 防抖函数
 * @param {Function} func 要防抖的函数
 * @param {number} delay 延迟时间（毫秒）
 * @returns {Function} 防抖后的函数
 */
export function debounce(func, delay = 300) {
  let timeoutId
  return function (...args) {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => func.apply(this, args), delay)
  }
}

/**
 * 节流函数
 * @param {Function} func 要节流的函数
 * @param {number} delay 节流间隔（毫秒）
 * @returns {Function} 节流后的函数
 */
export function throttle(func, delay = 300) {
  let lastTime = 0
  return function (...args) {
    const now = Date.now()
    if (now - lastTime >= delay) {
      lastTime = now
      return func.apply(this, args)
    }
  }
}

/**
 * 深拷贝对象
 * @param {any} obj 要拷贝的对象
 * @returns {any} 拷贝后的对象
 */
export function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj.getTime())
  if (obj instanceof Array) return obj.map(item => deepClone(item))
  if (typeof obj === 'object') {
    const clonedObj = {}
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        clonedObj[key] = deepClone(obj[key])
      }
    }
    return clonedObj
  }
}

/**
 * 检查是否为空值
 * @param {any} value 要检查的值
 * @returns {boolean} 是否为空
 */
export function isEmpty(value) {
  if (value === null || value === undefined) return true
  if (typeof value === 'string') return value.trim() === ''
  if (Array.isArray(value)) return value.length === 0
  if (typeof value === 'object') return Object.keys(value).length === 0
  return false
}

/**
 * 生成随机字符串
 * @param {number} length 字符串长度
 * @returns {string} 随机字符串
 */
export function randomString(length = 8) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length))
  }
  return result
}

/**
 * 获取文件扩展名
 * @param {string} filename 文件名
 * @returns {string} 扩展名
 */
export function getFileExtension(filename) {
  if (!filename || typeof filename !== 'string') return ''
  const lastDotIndex = filename.lastIndexOf('.')
  return lastDotIndex !== -1 ? filename.slice(lastDotIndex + 1).toLowerCase() : ''
}

/**
 * 验证手机号
 * @param {string} phone 手机号
 * @returns {boolean} 是否有效
 */
export function isValidPhone(phone) {
  const phoneRegex = /^1[3-9]\d{9}$/
  return phoneRegex.test(phone)
}

/**
 * 验证邮箱
 * @param {string} email 邮箱
 * @returns {boolean} 是否有效
 */
export function isValidEmail(email) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  return emailRegex.test(email)
}

/**
 * MD5加密函数
 * @param {string} string 要加密的字符串
 * @returns {string} MD5加密后的字符串
 * @author 王勇程 <laughskydragon@qq.com>
 */
export function md5(string) {
  function rotateLeft(lValue, iShiftBits) {
    return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits))
  }

  function addUnsigned(lX, lY) {
    const lX4 = lX & 0x40000000
    const lY4 = lY & 0x40000000
    const lX8 = lX & 0x80000000
    const lY8 = lY & 0x80000000
    const lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff)
    if (lX4 & lY4) {
      return lResult ^ 0x80000000 ^ lX8 ^ lY8
    }
    if (lX4 | lY4) {
      if (lResult & 0x40000000) {
        return lResult ^ 0xc0000000 ^ lX8 ^ lY8
      } else {
        return lResult ^ 0x40000000 ^ lX8 ^ lY8
      }
    } else {
      return lResult ^ lX8 ^ lY8
    }
  }

  function F(x, y, z) {
    return (x & y) | (~x & z)
  }
  function G(x, y, z) {
    return (x & z) | (y & ~z)
  }
  function H(x, y, z) {
    return x ^ y ^ z
  }
  function I(x, y, z) {
    return y ^ (x | ~z)
  }

  function FF(a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac))
    return addUnsigned(rotateLeft(a, s), b)
  }

  function GG(a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac))
    return addUnsigned(rotateLeft(a, s), b)
  }

  function HH(a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac))
    return addUnsigned(rotateLeft(a, s), b)
  }

  function II(a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac))
    return addUnsigned(rotateLeft(a, s), b)
  }

  function convertToWordArray(string) {
    let lWordCount
    const lMessageLength = string.length
    const lNumberOfWords_temp1 = lMessageLength + 8
    const lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64
    const lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16
    const lWordArray = Array(lNumberOfWords - 1)
    let lBytePosition = 0
    let lByteCount = 0
    while (lByteCount < lMessageLength) {
      lWordCount = (lByteCount - (lByteCount % 4)) / 4
      lBytePosition = (lByteCount % 4) * 8
      lWordArray[lWordCount] = lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)
      lByteCount++
    }
    lWordCount = (lByteCount - (lByteCount % 4)) / 4
    lBytePosition = (lByteCount % 4) * 8
    lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition)
    lWordArray[lNumberOfWords - 2] = lMessageLength << 3
    lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29
    return lWordArray
  }

  function wordToHex(lValue) {
    let wordToHexValue = ''
    let wordToHexValue_temp = ''
    let lByte, lCount
    for (lCount = 0; lCount <= 3; lCount++) {
      lByte = (lValue >>> (lCount * 8)) & 255
      wordToHexValue_temp = '0' + lByte.toString(16)
      wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2)
    }
    return wordToHexValue
  }

  function utf8Encode(string) {
    string = string.replace(/\r\n/g, '\n')
    let utftext = ''
    for (let n = 0; n < string.length; n++) {
      const c = string.charCodeAt(n)
      if (c < 128) {
        utftext += String.fromCharCode(c)
      } else if (c > 127 && c < 2048) {
        utftext += String.fromCharCode((c >> 6) | 192)
        utftext += String.fromCharCode((c & 63) | 128)
      } else {
        utftext += String.fromCharCode((c >> 12) | 224)
        utftext += String.fromCharCode(((c >> 6) & 63) | 128)
        utftext += String.fromCharCode((c & 63) | 128)
      }
    }
    return utftext
  }

  let x = Array()
  let k, AA, BB, CC, DD, a, b, c, d
  const S11 = 7,
    S12 = 12,
    S13 = 17,
    S14 = 22
  const S21 = 5,
    S22 = 9,
    S23 = 14,
    S24 = 20
  const S31 = 4,
    S32 = 11,
    S33 = 16,
    S34 = 23
  const S41 = 6,
    S42 = 10,
    S43 = 15,
    S44 = 21

  string = utf8Encode(string)
  x = convertToWordArray(string)
  a = 0x67452301
  b = 0xefcdab89
  c = 0x98badcfe
  d = 0x10325476

  for (k = 0; k < x.length; k += 16) {
    AA = a
    BB = b
    CC = c
    DD = d
    a = FF(a, b, c, d, x[k + 0], S11, 0xd76aa478)
    d = FF(d, a, b, c, x[k + 1], S12, 0xe8c7b756)
    c = FF(c, d, a, b, x[k + 2], S13, 0x242070db)
    b = FF(b, c, d, a, x[k + 3], S14, 0xc1bdceee)
    a = FF(a, b, c, d, x[k + 4], S11, 0xf57c0faf)
    d = FF(d, a, b, c, x[k + 5], S12, 0x4787c62a)
    c = FF(c, d, a, b, x[k + 6], S13, 0xa8304613)
    b = FF(b, c, d, a, x[k + 7], S14, 0xfd469501)
    a = FF(a, b, c, d, x[k + 8], S11, 0x698098d8)
    d = FF(d, a, b, c, x[k + 9], S12, 0x8b44f7af)
    c = FF(c, d, a, b, x[k + 10], S13, 0xffff5bb1)
    b = FF(b, c, d, a, x[k + 11], S14, 0x895cd7be)
    a = FF(a, b, c, d, x[k + 12], S11, 0x6b901122)
    d = FF(d, a, b, c, x[k + 13], S12, 0xfd987193)
    c = FF(c, d, a, b, x[k + 14], S13, 0xa679438e)
    b = FF(b, c, d, a, x[k + 15], S14, 0x49b40821)
    a = GG(a, b, c, d, x[k + 1], S21, 0xf61e2562)
    d = GG(d, a, b, c, x[k + 6], S22, 0xc040b340)
    c = GG(c, d, a, b, x[k + 11], S23, 0x265e5a51)
    b = GG(b, c, d, a, x[k + 0], S24, 0xe9b6c7aa)
    a = GG(a, b, c, d, x[k + 5], S21, 0xd62f105d)
    d = GG(d, a, b, c, x[k + 10], S22, 0x2441453)
    c = GG(c, d, a, b, x[k + 15], S23, 0xd8a1e681)
    b = GG(b, c, d, a, x[k + 4], S24, 0xe7d3fbc8)
    a = GG(a, b, c, d, x[k + 9], S21, 0x21e1cde6)
    d = GG(d, a, b, c, x[k + 14], S22, 0xc33707d6)
    c = GG(c, d, a, b, x[k + 3], S23, 0xf4d50d87)
    b = GG(b, c, d, a, x[k + 8], S24, 0x455a14ed)
    a = GG(a, b, c, d, x[k + 13], S21, 0xa9e3e905)
    d = GG(d, a, b, c, x[k + 2], S22, 0xfcefa3f8)
    c = GG(c, d, a, b, x[k + 7], S23, 0x676f02d9)
    b = GG(b, c, d, a, x[k + 12], S24, 0x8d2a4c8a)
    a = HH(a, b, c, d, x[k + 5], S31, 0xfffa3942)
    d = HH(d, a, b, c, x[k + 8], S32, 0x8771f681)
    c = HH(c, d, a, b, x[k + 11], S33, 0x6d9d6122)
    b = HH(b, c, d, a, x[k + 14], S34, 0xfde5380c)
    a = HH(a, b, c, d, x[k + 1], S31, 0xa4beea44)
    d = HH(d, a, b, c, x[k + 4], S32, 0x4bdecfa9)
    c = HH(c, d, a, b, x[k + 7], S33, 0xf6bb4b60)
    b = HH(b, c, d, a, x[k + 10], S34, 0xbebfbc70)
    a = HH(a, b, c, d, x[k + 13], S31, 0x289b7ec6)
    d = HH(d, a, b, c, x[k + 0], S32, 0xeaa127fa)
    c = HH(c, d, a, b, x[k + 3], S33, 0xd4ef3085)
    b = HH(b, c, d, a, x[k + 6], S34, 0x4881d05)
    a = HH(a, b, c, d, x[k + 9], S31, 0xd9d4d039)
    d = HH(d, a, b, c, x[k + 12], S32, 0xe6db99e5)
    c = HH(c, d, a, b, x[k + 15], S33, 0x1fa27cf8)
    b = HH(b, c, d, a, x[k + 2], S34, 0xc4ac5665)
    a = II(a, b, c, d, x[k + 0], S41, 0xf4292244)
    d = II(d, a, b, c, x[k + 7], S42, 0x432aff97)
    c = II(c, d, a, b, x[k + 14], S43, 0xab9423a7)
    b = II(b, c, d, a, x[k + 5], S44, 0xfc93a039)
    a = II(a, b, c, d, x[k + 12], S41, 0x655b59c3)
    d = II(d, a, b, c, x[k + 3], S42, 0x8f0ccc92)
    c = II(c, d, a, b, x[k + 10], S43, 0xffeff47d)
    b = II(b, c, d, a, x[k + 1], S44, 0x85845dd1)
    a = II(a, b, c, d, x[k + 8], S41, 0x6fa87e4f)
    d = II(d, a, b, c, x[k + 15], S42, 0xfe2ce6e0)
    c = II(c, d, a, b, x[k + 6], S43, 0xa3014314)
    b = II(b, c, d, a, x[k + 13], S44, 0x4e0811a1)
    a = II(a, b, c, d, x[k + 4], S41, 0xf7537e82)
    d = II(d, a, b, c, x[k + 11], S42, 0xbd3af235)
    c = II(c, d, a, b, x[k + 2], S43, 0x2ad7d2bb)
    b = II(b, c, d, a, x[k + 9], S44, 0xeb86d391)
    a = addUnsigned(a, AA)
    b = addUnsigned(b, BB)
    c = addUnsigned(c, CC)
    d = addUnsigned(d, DD)
  }

  const temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d)
  return temp.toLowerCase()
}

/**
 * 检查网络状态
 * @returns {Promise<boolean>} 网络是否可用
 * @author 王勇程 <laughskydragon@qq.com>
 */
export function checkNetworkStatus() {
  return new Promise((resolve) => {
    // #ifdef MP-WEIXIN
    uni.getNetworkType({
      success: (res) => {
        // 网络类型：wifi、2g、3g、4g、5g、ethernet、unknown、none
        resolve(res.networkType !== 'none')
      },
      fail: () => {
        // 获取失败时默认认为有网络
        resolve(true)
      }
    })
    // #endif
    
    // #ifdef H5
    resolve(navigator.onLine)
    // #endif
    
    // #ifdef APP-PLUS
    uni.getNetworkType({
      success: (res) => {
        resolve(res.networkType !== 'none')
      },
      fail: () => {
        resolve(true)
      }
    })
    // #endif
  })
}

import APP_CONFIG from '@/config'

export function buildPictureUrl(path) {
  if (!path) return ''
  const p = String(path).replace(/\\/g, '/').replace(/^\//, '')
  return `${APP_CONFIG.BASE_URL}/upload/picture/${p}`
}

export function normalizeImageUrl(input) {
  if (!input) return ''
  const s = String(input)
  if (/^https?:\/\//.test(s)) return s
  // 如果已经是相对路径（包含/upload/picture/），直接拼接基础URL
  if (s.startsWith('/upload/picture/')) {
    return `${APP_CONFIG.BASE_URL}${s}`
  }
  return buildPictureUrl(s)
}
